#pragma once
#include <iostream>
#include <string>
#include <sstream>
#include <jsoncpp/json/json.h>

// #define SELF

namespace protocol_ns
{
    static const std::string SEP = "\r\n";
    static const std::string InLineSEP = " ";

    std::string EnCode(const std::string &jsonStr)
    {
        int len = jsonStr.size();
        std::string message = std::to_string(len) + SEP + jsonStr + SEP;
        return message;
    }
    // len\r\n ........ \r\n
    std::string DeCode(std::string &inbuffer)
    {
        auto pos = inbuffer.find(SEP);
        if (pos == std::string::npos)
            return "";
        std::string lenStr = inbuffer.substr(0, pos);
        if (lenStr.empty())
            return "";
        int len = std::stoi(lenStr);
        int total = lenStr.size() + len + 2 * SEP.size();
        if (total > inbuffer.size())
            return "";
        std::string ret = inbuffer.substr(pos + SEP.size(), len);
        inbuffer.erase(0, total);
        return ret;
    }

    struct Request
    {
    public:
        Request(int num1, int num2, char oper)
            : _leftOperNum(num1), _rightOperNum(num2), _oper(oper)
        {
        }
        bool Serialize(std::string &out)
        {
#ifdef SELF
            out += std::to_string(_leftOperNum);
            out += InLineSEP;
            out += _oper;
            out += InLineSEP;
            out += std::to_string(_rightOperNum);
            return true;
#else
            Json::Value root;
            root["leftOperNum"] = _leftOperNum;
            root["rightOperNum"] = _rightOperNum;
            root["oper"] = _oper;

            Json::FastWriter writer;
            out = writer.write(root);
            return true;
#endif
        }
        bool DeSerialize(const std::string &in)
        {
#ifdef SELF
            std::stringstream ss(in);
            std::string leftOperNum, oper, rightOperNum;
            ss >> leftOperNum >> oper >> rightOperNum;
            if(leftOperNum.empty() || oper.empty() || rightOperNum.empty())
                return false;
            _leftOperNum = std::stoi(leftOperNum);
            _oper = oper[0];
            _rightOperNum = std::stoi(rightOperNum);
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (!res)
                return false;

            _leftOperNum = root["leftOperNum"].asInt();
            _rightOperNum = root["rightOperNum"].asInt();
            _oper = root["oper"].asInt();
            return true;
#endif
        }
        ~Request()
        {
        }

        int _leftOperNum;
        int _rightOperNum;
        char _oper;
    };

    struct Response
    {
    public:
        Response(int res, int code)
            : _result(res), _code(code)
        {
        }
        bool Serialize(std::string &out)
        {
#ifdef SELF
            out += std::to_string(_result);
            out += InLineSEP;
            out += std::to_string(_code);
            return true;
#else
            Json::Value root;
            root["result"] = _result;
            root["code"] = _code;

            Json::FastWriter writer;
            out = writer.write(root);
            return true;
#endif
        }
        bool DeSerialize(const std::string &in)
        {
#ifdef SELF
            std::stringstream ss(in);
            std::string result, code;
            ss >> result >> code;
            if(result.empty() || code.empty())
                return false;
            _result = std::stoi(result);
            _code = std::stoi(code);
            return true;
#else
            Json::Value root;
            Json::Reader reader;
            bool res = reader.parse(in, root);
            if (!res)
                return false;

            _result = root["result"].asInt();
            _code = root["code"].asInt();
            return true;
#endif
        }
        ~Response()
        {
        }

        int _result;
        int _code;
    };

}